package com.fang.transfer.file.client.transfer;

import com.fang.transfer.file.client.AppContext;
import com.fang.transfer.file.client.connection.UdpUtil;
import com.fang.transfer.file.client.util.IndexUtil;
import com.fang.transfer.file.common.code.ClientSendCode;
import com.fang.transfer.file.common.model.TransferFileRequest;
import com.fang.transfer.file.common.model.User;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.DatagramPacket;
import java.net.InetSocketAddress;

public class UdpService {

    private TransferFileRequest request;

    private UdpUtil udpUtil;
    private RandomAccessFile rw;
    private InetSocketAddress targetUserAddr;

    private Thread udpReceiveThread;

    public UdpService(TransferFileRequest request) throws Exception {
        this.request = request;
        initUDP();
    }

    private void initUDP() throws Exception {
        init();
        udpUtil = new UdpUtil();
        udpReceiveThread = new Thread() {
            @Override
            public void run() {
                try {
                    receive();
                } catch (InterruptedException exception) {
                    System.out.println("UDP 接收线程结束");
                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    try {
                        close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        udpReceiveThread.start();
    }

    public void initSendUserAddr() {
        String role = request.getRole();
        User user = "1".equals(role) ? request.getReceiveUser() : request.getSendUser();
        this.targetUserAddr = new InetSocketAddress(user.getHost(), user.getPort());
    }

    private void receive() throws Exception {
        byte[] data = new byte[UdpUtil.PACKAGE_LENGTH];
        DatagramPacket packet = new DatagramPacket(data, data.length);
        while (true) {
            udpUtil.receive(packet);
            int length = packet.getLength();
            byte index1 = data[0];
            byte index2 = data[1];
            if (index1 != -1 || index2 != -1) {
                //接收文件
                receiveFile(data, length);
                continue;
            }
            note(data, length);
        }
    }

    private void note(byte[] data, int length) {
        byte code = data[2];
        switch (code) {
            case UdpUtil.HOLD:
                udpHold();
                break;
            default:
                System.out.println("未识别UDP请求  code:" + code);

        }
    }

    private void udpHold() {
        System.out.println("收到打洞请求" + request.getId());
        AppContext.tcpUtil.writeAndFlush(ClientSendCode.UPD_HOLE_SUCCESS, request);
    }

    private void receiveFile(byte[] data, int length) throws Exception {
        int index = IndexUtil.getIndexByByteArr(data);
        System.out.println("收到下标:" + index);
        this.rw.seek(index * (UdpUtil.PACKAGE_LENGTH - 2));
        this.rw.write(data, 2, length - 2);

        request.addCurCount(index);
    }


    private void close() throws IOException {
        if (this.rw != null) {
            rw.close();
        }
        udpReceiveThread.interrupt();
        AppContext.randomAccessFileMap.remove(request.getId());
        AppContext.udpServiceMap.remove(request.getId());
        AppContext.transferFileRequestMap.remove(request.getId());
    }

    private void init() throws Exception {
        File file = null;
        if ("1".equals(this.request.getRole())) {
            file = new File(request.getPath());
        } else {
            file = new File("c://temp2");
            if (!file.exists()) {
                file.mkdirs();
            }
            file = new File(file, request.getName());
        }

        this.rw = new RandomAccessFile(file, "rw");
        AppContext.randomAccessFileMap.put(request.getId(), rw);
        request.initParam();
    }

    public void holeSend() throws Exception {
        udpUtil.sendInfoTargetUser(this.targetUserAddr, UdpUtil.HOLD, request);
    }

    public void sendData(DatagramPacket packet) throws IOException {
        udpUtil.sendData(packet);
    }

    public void sendServiceInfo(String updAddrUpdate, TransferFileRequest request) throws Exception {
        udpUtil.sendServiceInfo(updAddrUpdate, request);
    }
}
